<template>
  <div :class="`app-container ${isShowSider ? '' : 'list-hide'}`">
    <el-row :gutter="20">
      <splitpanes
        :horizontal="this.$store.getters.device === 'mobile'"
        class="default-theme"
      >
        <!--历史会话列表-->
        <pane v-show="!smallWindow" :size="isShowSider ? '20' : '0'">
          <el-col class="an-qu sider">
            <div v-if="isShowSider">
              <div class="sider-header">
                <div class="show-left">{{ title }}</div>
                <div class="show-right sider-icon">
                  <el-popover
                    placement="right"
                    trigger="hover"
                    content="收起边栏"
                    popper-class="comment-btn-popover"
                  >
                    <svg-icon
                      slot="reference"
                      style="width: 22px; height: 22px; margin-right: 8px"
                      icon-class="sidebarcebianlan"
                      @click="collapseHistoryList"
                    />
                  </el-popover>
                </div>
              </div>
            </div>
            <div class="sider-icon posi" v-else>
              <el-popover
                placement="right"
                trigger="hover"
                content="打开边栏"
                popper-class="comment-btn-popover"
              >
                <svg-icon
                  slot="reference"
                  style="width: 22px; height: 22px; margin-right: 8px"
                  icon-class="sidebarcebianlan"
                  @click="expandHistoryList"
                />
              </el-popover>
            </div>
            <ConversationList
              :conversations="conversations"
              :selectedConversation="selectedConversation"
              @select-conversation="selectConversation"
              @delete-conversation="deleteConversation"
              @change-new-conversation="changeNewConversation"
              @update-conversation="updateConversation"
            />
          </el-col>
        </pane>
        <!--聊天窗口-->
        <pane :size="isShowSider && !smallWindow ? '80' : '100'">
          <el-col class="an-qu">
            <el-select
              class="conversation-select"
              v-model="agentInputId"
              @change="selectAgent"
              @visible-change="selectVisibleChange"
              placeholder="请选择"
            >
              <template #prefix>
                <span class="agent-icon">
                  <i class="el-icon-sort"></i>
                </span>
              </template>
              <el-option
                v-for="item in agentList"
                :key="item.value"
                :label="item.name"
                :value="item.id"
              >
              </el-option>
            </el-select>
            <ChatWindow
              @send-message="sendMessage"
              @select-agent="selectAgent"
              @change-selectedConversation="changeSelectedConversation"
              @interrupt-request="interruptRequest"
              @update-conversation="updateConversation"
              :displayMessages="messageList"
              :selectedConversation="selectedConversation"
              :aqLoading="aqLoading"
              :smallWindow="smallWindow"
              :referenceList1="referenceList"
            />
          </el-col>
        </pane>
      </splitpanes>
    </el-row>
  </div>
</template>

<script>
import ConversationList from "./components/ConversationList.vue";
import ChatWindow from "./components/ChatWindow.vue";
import { getToken } from "@/utils/auth";
import { fetchEventSource } from "@microsoft/fetch-event-source";
import {
  getConversations,
  addApiConversation,
  getConversationMessages,
  updateTitle,
  delConversation,
  getSelect,
} from "@/api/counterAssistant/session";
import { getUserProfile } from "@/api/system/user";
import {
  parseArray,
  formatDate,
  handleData,
  processQueue,
} from "@/utils/index";

import { Splitpanes, Pane } from "splitpanes";
import "splitpanes/dist/splitpanes.css";
let functionQueueObj = {};
let answerObj = {};
export default {
  name: "Assistant",
  components: {
    Splitpanes,
    Pane,
    ConversationList,
    ChatWindow,
  },
  props: {
    smallWindow: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      title: "KBRuns问答助手",
      agentInputId: "",
      isShowSider: true,
      // 会话历史列表
      conversations: [],
      // 当前会话
      selectedConversation: null,
      agentList: [],
      userId: null,
      roleId: null,
      messageList: [],
      // agentId: 0,
      // chatId: 0,
      id: 0,
      aqLoading: false, // 获取会话中
      // anserLoading: false, // 是否正在回答中
      // ctrlAbout: null,
      referenceList: [],
      roleIdList: {},
    };
  },
  created() {
    this.getInfo();
  },
  methods: {
    collapseHistoryList() {
      this.isShowSider = false;
    },
    expandHistoryList() {
      this.isShowSider = true;
    },
    selectVisibleChange(isVisble) {
      if(isVisble) {
        getSelect({ roleIdList: this.roleIdList }).then((res) => {
          if (res.code == 200) {
            this.agentList = res.rows;
          }
        });
      }
    },
    // 根据用户信息，获取agent
    getInfo() {
      getUserProfile().then((response) => {
        this.roleIdList = response.data.roles.map((role) => role.roleId);
        getSelect({ roleIdList: this.roleIdList }).then((res) => {
          if (res.code == 200) {
            this.agentList = res.rows;
            if (this.agentList.length > 0) {
              this.agentInputId = this.agentList[0].id;
              // this.agentId = this.agentList[0].ragAgentId;
              // this.chatId = this.agentList[0].chatId;
              this.id = this.agentList[0].id;
            }
          }
        });
        this.userId = response.data.userId;
        this.fetchConversations(response.data.userId);
      });
    },
    // 切换agent
    selectAgent(id) {
      this.agentInputId = id;
      const agent = this.agentList.find((item) => item.id == id);
      if (agent) {
        // this.agentId = agent.ragAgentId;
        // this.chatId = agent.chatId;
        this.id = agent.id;
      }
    },
    // 流式回答时的滚动条
    scrollToBottom() {
      this.$nextTick(() => {
        const container = document.querySelector(
          ".chat-detail-scroll-container"
        );
        if (container) {
          container.scrollTop = container.scrollHeight + 1000;
        }
      });
    },
    // 获取问答列表的滚动条(问答页面在最底部时才滚动)
    scrollAtBottom() {
      this.$nextTick(() => {
        const container = document.querySelector(
          ".chat-detail-scroll-container"
        );
        if (container) {
          if (
            container.scrollTop + container.clientHeight + 100 >
            container.scrollHeight
          ) {
            container.scrollTop = container.scrollHeight;
          }
        }
      });
    },
    // 终止问答
    interruptRequest() {
      answerObj[this.selectedConversation.id].anserLoading = false;
      functionQueueObj[this.selectedConversation.id] = [];
      answerObj[this.selectedConversation.id].ctrlAbout &&
        answerObj[this.selectedConversation.id].ctrlAbout.abort &&
        answerObj[this.selectedConversation.id].ctrlAbout.abort();
    },
    // 切换点赞点踩状态
    changeSelectedConversation(id, status) {
      this.messageList.forEach((item) => {
        if (item.qaId === id) {
          item.isLike = status;
        }
      });
    },
    // 问答提交逻辑
    async sendMessage(messageContent, answerStatus) {
      let sessionId = -1;
      if (!this.selectedConversation) {
        const param = {
          name: "新会话",
          language: "cn",
          creatBy: this.userId,
          firstQuestion: messageContent,
        };
        // 创建新会话
        const response = await addApiConversation(param);
        if (response.code === 200) {
          sessionId = response.data.id;
          const newConversation = {
            id: response.data.id,
            title: response.data.name,
            createTime: formatDate(new Date()),
            messageList: [],
          };
          this.selectedConversation = newConversation;
          this.conversations.unshift(newConversation);
          this.messageList = newConversation.messageList;
        }
      } else {
        sessionId = this.selectedConversation.id;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
      const conversationTemp = this.getConversationTemp(sessionId);
      answerObj[sessionId] = {
        role: "assistant",
        content: "",
        reasoningContent: "",
        isLike: null,
        question: messageContent,
        sessionId: this.selectedConversation.id,
        referenceList: [],
        anserLoading: true,
        ctrlAbout: new AbortController(),
      };

      conversationTemp.messageList.push({
        role: "user",
        content: messageContent,
      });
      conversationTemp.messageList.push(answerObj[sessionId]);

      // 发送 SSE 请求
      const that = this;
      const proxyUrl = process.env.VUE_APP_BASE_API + "/qa/questionStream";
      // 创建一个函数队列
      functionQueueObj[sessionId] = [];
      const functionQueue = functionQueueObj[sessionId];
      answerObj[sessionId].isProcessingQueue = false;
      try {
        fetchEventSource(proxyUrl, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Accept: "text/event-stream",
            Authorization: "Bearer " + getToken(),
          },
          signal: answerObj[sessionId].ctrlAbout.signal,
          body: JSON.stringify({
            // agentId: this.agentId,
            // chatId: this.chatId,
            id: this.id,
            streaming: true,
            queryText: messageContent,
            answerStatus: answerStatus,
            language: "zh",
            sessionId,
          }),
          onmessage(ev) {
            // 清空内容
            let trimData = "";
            let reasoningContent = "";
            try {
              const parsedData = JSON.parse(ev.data);
              if (parsedData.sourceDocs) {
                const tempData = parseArray(parsedData.sourceDocs);
                that.referenceList = tempData;
                answerObj[sessionId].referenceList = tempData;
                answerObj[sessionId].qaId = parsedData.answerId;
                answerObj[sessionId].ctrlAbout.abort();
                const wrappedCallback = () =>
                  handleData("end", () => {
                    answerObj[sessionId].anserLoading = false;
                  });
                functionQueue.push(wrappedCallback);
                processQueue(functionQueue, answerObj[sessionId]); // 尝试立即处理队列（如果当前没有在处理）
                return;
              }
              if (parsedData.think) {
                reasoningContent = parsedData.msg;
                // 直接显示在页面的代码
                const wrappedCallback = () =>
                  handleData(reasoningContent, (data) => {
                    const messageData = answerObj[sessionId].reasoningContent;
                    answerObj[sessionId].reasoningContent = messageData + data;
                    that.$nextTick(() => {
                      that.scrollAtBottom();
                    });
                  });
                functionQueue.push(wrappedCallback);
                processQueue(functionQueue, answerObj[sessionId]); // 尝试立即处理队列（如果当前没有在处理）
              } else {
                trimData = parsedData.msg;
                // 直接显示在页面的代码
                const wrappedCallback1 = () =>
                  handleData(trimData, (data) => {
                    const messageData = answerObj[sessionId].content;
                    answerObj[sessionId].content = messageData + data;
                    that.$nextTick(() => {
                      that.scrollAtBottom();
                    });
                  });
                functionQueue.push(wrappedCallback1);
                processQueue(functionQueue, answerObj[sessionId]); // 尝试立即处理队列（如果当前没有在处理）
              }
            } catch (e) {
              console.log('catch',e);
              answerObj[sessionId].anserLoading = false;
              answerObj[sessionId].ctrlAbout.abort();
              functionQueueObj[that.selectedConversation.id] = [];
            }
          },
          onclose() {
            answerObj[sessionId].anserLoading = false;
            answerObj[sessionId].ctrlAbout.abort();
            functionQueueObj[that.selectedConversation.id] = [];
          },
          onerror(err) {
            answerObj[sessionId].anserLoading = false;
            answerObj[sessionId].ctrlAbout.abort();
            functionQueueObj[that.selectedConversation.id] = [];
          },
        });
      } catch (error) {
        // console.log('catch111',error);
        answerObj[sessionId].anserLoading = false;
        answerObj[sessionId].ctrlAbout.abort();
        functionQueueObj[that.selectedConversation.id] = [];
      }
    },
    // 获取会话列表
    fetchConversations(userId) {
      const params = {
        userId,
      };
      getConversations(params).then((response) => {
        this.conversations = response.rows.map((conversation) => ({
          id: conversation.id,
          title: conversation.name,
          createTime: conversation.createTime,
        }));
      });
    },

    // 选中会话
    selectConversation(conversation) {
      if (
        this.selectedConversation &&
        this.selectedConversation.id === conversation.id
      )
        return;
      this.selectedConversation = conversation;
      const conversationTemp = this.getConversationTemp(conversation.id);
      if (conversationTemp.hasOwnProperty("messageList")) {
        this.messageList = conversationTemp.messageList;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } else {
        this.fetchConversationMessages(conversation.id, conversationTemp);
      }
    },
    // 获取会话临时对象
    getConversationTemp(id) {
      const conversationTemp = this.conversations.find(
        (item) => item.id === id
      );
      return conversationTemp;
    },
    // 获取会话消息
    fetchConversationMessages(conversationId, conversationTemp) {
      const params = {
        sessionId: conversationId,
      };
      this.aqLoading = true;
      getConversationMessages(params).then((response) => {
        // this.messageList = [];
        conversationTemp.messageList = [];
        response.rows.length > 0 &&
          response.rows.forEach((message) => {
            // 使用正则表达式匹配 <think> 和 </think> 标签内的内容
            const thinkRegex = /<think>([\s\S]*?)<\/think>/;
            const match = message.answerContent.match(thinkRegex);

            let thinkContent = "";
            let content = "";
            if (match) {
              thinkContent = match[1].trim(); // 获取 <think> 标签内的内容
              content = message.answerContent.replace(thinkRegex, "").trim(); // 获取剩余内容
            } else {
              thinkContent = ""; // 如果没有找到 <think> 标签，则 thinkContent 为空
              content = message.answerContent.trim(); // 剩余内容为整个字符串
            }
            // this.messageList.push(
            conversationTemp.messageList.push(
              {
                role: "user",
                content: message.questionContent,
              },
              {
                role: "assistant",
                content: content,
                reasoningContent: thinkContent,
                question: message.questionContent,
                qaId: message.id,
                sessionId: message.sessionId,
                isLike: message.isLike,
                referenceList: message.referenceList?parseArray(message.referenceList):[],
                anserLoading: false,
              }
            );
          });
        this.messageList = conversationTemp.messageList;
        this.aqLoading = false;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      });
    },
    // 删除会话
    deleteConversation(conversationId) {
      this.$confirm("删除后，该对话将不可恢复。确认删除吗？", "永久删除对话", {
        type: "warning",
      }).then(() => {
        delConversation(conversationId).then(() => {
          this.conversations = this.conversations.filter(
            (conv) => conv.id !== conversationId
          );
          answerObj[conversationId] = null;
          functionQueueObj[conversationId] = null;
          if (
            this.selectedConversation &&
            this.selectedConversation.id === conversationId
          ) {
            this.messageList = [];
            // this.interruptRequest();
            this.selectedConversation = null;
          }
          this.$modal.msgSuccess("删除成功");
        });
      });
    },
    // 切换到新会话
    changeNewConversation() {
      if (!this.selectedConversation) return;
      this.selectedConversation = null;
      this.messageList = [];
    },

    // 修改会话
    updateConversation(conversationId, newTitle) {
      const conversation = this.conversations.find(
        (conv) => conv.id === conversationId
      );
      if (!conversation || conversation.title === newTitle) return;
      const data = {
        id: conversationId,
        name: newTitle,
      };
      updateTitle(data).then((response) => {
        conversation.title = newTitle;
      });
    },
  },
};
</script>

<style scoped lang="scss">
.app-container {
  padding: 0;
  &.list-hide {
    .splitpanes__pane {
      overflow: initial;
      .an-qu {
        overflow: initial;
      }
    }
  }
  .show-left {
    font-size: 20px;
  }
  .el-row {
    margin: 0 !important;
  }
  .an-qu {
    height: calc(100vh - 84px);
    //overflow: auto;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    position: relative;
    .conversation-select {
      // margin-right: 10px; /* 为 el-select 和 el-input 之间添加间距 */
      position: absolute;
      top: 6px;
      right: 16px;
      z-index: 1000;
    }
    &.sider {
      // background: #fafafa;
      .posi {
        position: absolute;
        top: 10px;
        left: 20px;
        z-index: 1000;
      }
      .sider-header {
        padding: 10px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 100%;
        margin-top: 20px;
      }
    }
    .sider-icon {
      cursor: pointer;
    }
  }
}
</style>
<style lang="scss">
.conversation-select {
  .el-input__prefix {
    top: 10px;
    .agent-icon {
      padding: 2px;
      border-radius: 50%;
      border: 1px solid #777;
      i {
        transform: rotate(90deg);
        font-weight: 700;
        color: #777;
      }
    }
  }
  .el-input__inner {
    border: none;
    /* background: #ccc; */
    border-radius: 10px;
    width: 150px;
    &:hover {
      background: rgba(219, 234, 254, 0.4);
    }
  }
}
</style>